package pers.bc.utils.apach;

import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.spi.LoggingEvent;

/**
 * 
 **
 * @qualiFild pers.bc.utils.apach.RollingFileAppenderBc.java<br>
 * @author：LiBencheng<br>
 * @date Created on 2018年8月15日<br>
 * @version 1.0<br>
 */
public class RollingFileAppenderBc extends FileAppender
{
    protected long maxFileSize;
    protected int maxBackupIndex;
    private long nextRollover;
    
    public RollingFileAppenderBc()
    {
        this.maxFileSize = 10485760L;
        this.maxBackupIndex = 1;
        this.nextRollover = 0L;
    }
    
    public RollingFileAppenderBc(final Layout layout, final String filename, final boolean append) throws IOException
    {
        super(layout, filename, append);
        this.maxFileSize = 10485760L;
        this.maxBackupIndex = 1;
        this.nextRollover = 0L;
    }
    
    public RollingFileAppenderBc(final Layout layout, final String filename) throws IOException
    {
        super(layout, filename);
        this.maxFileSize = 10485760L;
        this.maxBackupIndex = 1;
        this.nextRollover = 0L;
    }
    
    public int getMaxBackupIndex()
    {
        return this.maxBackupIndex;
    }
    
    public long getMaximumFileSize()
    {
        return this.maxFileSize;
    }
    
    public void rollOver()
    {
        if (this.qw != null)
        {
            final long size = ((CountingQuietWriter) this.qw).getCount();
            LogLog.debug("rolling over count=" + size);
            this.nextRollover = size + this.maxFileSize;
        }
        LogLog.debug("maxBackupIndex=" + this.maxBackupIndex);
        boolean renameSucceeded = true;
        if (this.maxBackupIndex > 0)
        {
            int ii = 0;
            String newFilePath = null;
            File newFile = null;
            File oldFile = new File(fileName);
            String fileName = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            String[] split = this.fileName.split("\\.");
            String prefix = split[0] + fileName;
            String suffix = split[1];
            do
            {
                newFilePath = prefix + " {" + ii + "}." + suffix;
                newFile = new File(newFilePath);
                ii++;
            }
            while (newFile.exists());
            closeFile();
            renameSucceeded = oldFile.renameTo(newFile);
            if (renameSucceeded)
            {
                final File target = new File(prefix + " {" + ii + "}." + suffix);
                this.closeFile();
                File file = new File(this.fileName);
                LogLog.debug("Renaming file " + file + " to " + target);
                renameSucceeded = file.renameTo(target);
                if (!renameSucceeded)
                {
                    try
                    {
                        this.setFile(this.fileName, true, this.bufferedIO, this.bufferSize);
                    }
                    catch (final IOException e)
                    {
                        if (e instanceof InterruptedIOException)
                        {
                            Thread.currentThread().interrupt();
                        }
                        LogLog.error("setFile(" + this.fileName + ", true) call failed.", (Throwable) e);
                    }
                }
            }
        }
        if (renameSucceeded)
        {
            try
            {
                this.setFile(this.fileName, false, this.bufferedIO, this.bufferSize);
                this.nextRollover = 0L;
            }
            catch (final IOException e)
            {
                if (e instanceof InterruptedIOException)
                {
                    Thread.currentThread().interrupt();
                }
                LogLog.error("setFile(" + this.fileName + ", false) call failed.", (Throwable) e);
            }
        }
    }
    
    protected void closeFile()
    {
        if (this.qw != null)
        {
            try
            {
                this.qw.close();
            }
            catch (final IOException e)
            {
                if (e instanceof InterruptedIOException)
                {
                    Thread.currentThread().interrupt();
                }
                LogLog.error("Could not close " + this.qw, (Throwable) e);
            }
        }
    }
    
    public synchronized void setFile(final String fileName, final boolean append, final boolean bufferedIO, final int bufferSize)
            throws IOException
    {
        super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
        if (append)
        {
            final File f = new File(fileName);
            ((CountingQuietWriter) this.qw).setCount(f.length());
        }
    }
    
    public void setMaxBackupIndex(final int maxBackups)
    {
        this.maxBackupIndex = maxBackups;
    }
    
    public void setMaximumFileSize(final long maxFileSize)
    {
        this.maxFileSize = maxFileSize;
    }
    
    public void setMaxFileSize(final String value)
    {
        this.maxFileSize = OptionConverter.toFileSize(value, this.maxFileSize + 1L);
    }
    
    protected void setQWForFiles(final Writer writer)
    {
        this.qw = (QuietWriter) new CountingQuietWriter(writer, this.errorHandler);
    }
    
    protected void subAppend(final LoggingEvent event)
    {
        super.subAppend(event);
        if (this.fileName != null && this.qw != null)
        {
            final long size = ((CountingQuietWriter) this.qw).getCount();
            if (size >= this.maxFileSize && size >= this.nextRollover)
            {
                this.rollOver();
            }
        }
    }
}
